﻿using MQTTnet.Client.Options;
using MQTTnet.Client;
using MQTTnet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;
using MQTTnet.Packets;
using PHMEE.MqttClient.MqttBusinessCommand;
using System.Reflection;

namespace PHMEE.MqttClient
{
    public class DtCollectionWorker : BackgroundService
    {
        private readonly IConfiguration _configuration;

        private readonly ILogger<DtCollectionWorker> _logger;
        private readonly IMqttClientOptions _options;
        private readonly IMqttFactory _mqttFactory;
        private IMqttClient _mqttClient;
        private readonly MqttTopicFilter _mqttTopicFilter;
        private readonly MqttUserProperty _mqttUserProperty;
        private readonly ILoggerFactory _loggerFactory;
        private readonly IServiceScopeFactory _serviceScopeFactory;

        //订阅主题
        //private string subscribetopic = "Doton/Online/#";
        //订阅主题前缀
        private readonly string Prefix;

        public DtCollectionWorker(IConfiguration configuration, ILogger<DtCollectionWorker> logger, ILoggerFactory loggerFactory, IServiceScopeFactory serviceScopeFactory)
        {
            _configuration = configuration;
            _logger = logger;
            _loggerFactory = loggerFactory;
            string Server = _configuration.GetValue<string>("MqttClient:Host")!;
            int Port = _configuration.GetValue<int>("MqttClient:Port")!;
            string username = _configuration.GetValue<string>("MqttClient:UserName")!;
            string password = _configuration.GetValue<string>("MqttClient:Password")!;
            Prefix = _configuration.GetValue<string>("MqttClient:Prefix")!;

            _options = new MqttClientOptionsBuilder()
                .WithClientId(Guid.NewGuid().ToString())
                .WithCredentials(username, password)
                .WithCleanSession(true)
                .WithTcpServer(Server, Port)
                .Build();

            _mqttFactory = new MqttFactory();
            _mqttClient = _mqttFactory.CreateMqttClient();

            _serviceScopeFactory = serviceScopeFactory;

            _mqttTopicFilter = new MqttTopicFilter
            {
                Topic = Prefix + "/Online/#",
                QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce
            };
            _mqttUserProperty = new MqttUserProperty(username, password);
        }

        public override async Task StartAsync(CancellationToken cancellationToken)
        {
            //断连，重连
            _mqttClient.UseDisconnectedHandler(async arg =>
            {
                _logger.LogInformation("已断开与MQTT Broker的连接。正在尝试重新连接...");
                if (cancellationToken.IsCancellationRequested || _mqttClient.IsConnected) return;
                await _mqttClient.ReconnectAsync(cancellationToken);
            });
            _mqttClient.UseConnectedHandler(arg =>
            {
                _logger.LogInformation($"\n\n连接状态：{arg.ConnectResult.ResultCode}\n\n");
            });
            //接收消息事件
            _mqttClient.UseApplicationMessageReceivedHandler(async conten =>
            {
                await HandelDataAsync(conten);
            });

            await _mqttClient.ConnectAsync(_options, cancellationToken);
            await _mqttClient.SubscribeAsync(new MqttClientSubscribeOptions
            {
                TopicFilters = new List<MqttTopicFilter> { _mqttTopicFilter },
                UserProperties = new List<MqttUserProperty> { _mqttUserProperty }
            }, cancellationToken);

            await base.StartAsync(cancellationToken);
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                await Task.Delay(5000, stoppingToken);
            }
        }
        /// <summary>
        ///接收到报文之后进行业务处理 
        /// </summary>
        private async Task HandelDataAsync(MqttApplicationMessageReceivedEventArgs conten)
        {
            using (var scope = _serviceScopeFactory.CreateScope())
            {
                try
                {
                    string business = conten.ApplicationMessage.Topic.Split('/')[3].Trim();
                    //Console.WriteLine($"================={business}({DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")})=================");
                    //Console.WriteLine("\n");
                    //if (conten.ApplicationMessage.Topic.Split('/')[3].Trim() == "Register")
                    //{
                    //得到示例81001001/IndexData/59945(采集站唯一标识，业务关键字，通讯Id)
                    string[] strArrs = conten.ApplicationMessage.Topic.Split(new[] { Prefix + "/Online/" }, StringSplitOptions.None);
                    if (strArrs.Length < 1)
                    {
                        return;
                    }
                    string[] EffectiveStr = strArrs[1].Split('/');
                    //采集站唯一标识Code
                    string SN = EffectiveStr[0];
                    //业务关键字
                    string CMD = EffectiveStr[1];
                    string MessageId = "";
                    if (EffectiveStr.Length > 2)
                        MessageId = EffectiveStr[2];
                    Console.WriteLine("========" + CMD + "========");
                    Type? commandType = typeof(RegisterCommand).GetTypeInfo().Assembly.GetType("PHMEE.MqttClient.MqttBusinessCommand." + CMD + "Command");
                    if (commandType != null)
                    {
                        var commandInstance = scope.ServiceProvider.GetRequiredService(commandType) as BaseCommand;
                        if (commandInstance != null)
                        {
                            //获取特定类的日志记录实例
                            var commandLogger = _loggerFactory.CreateLogger(commandType);
                            byte[] payload = conten.ApplicationMessage.Payload;
                            if (payload == null)
                                payload = Array.Empty<byte>();
                            commandInstance.MessageId = MessageId;
                            commandInstance.SN = SN;
                            commandInstance.ClientId = conten.ClientId;
                            commandInstance.SetLogger(commandLogger);// 将创建的日志记录器设置给 Command 实例
                            commandInstance.ReplyAsyncDelegacy = (topic, resPayload) =>
                            {
                                return _mqttClient.PublishAsync(new MqttApplicationMessageBuilder()
                                .WithTopic(Prefix + "/" + topic)
                                .WithPayload(resPayload)
                                .WithAtLeastOnceQoS()
                                .Build());
                            };
                            await commandInstance.ExecuteAsync(Encoding.UTF8.GetString(payload));
                            //如果需要回复 则回复
                            if (commandInstance.isReplay)
                                await commandInstance.ReplyAsync();
                        }
                    }
                    //}
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex.ToString());
                }
            }
            await Task.CompletedTask;
        }

        public override async Task StopAsync(CancellationToken cancellationToken)
        {
            await _mqttClient.UnsubscribeAsync(new MqttClientUnsubscribeOptions
            {
                TopicFilters = new List<string> { _mqttTopicFilter.Topic },
            }, cancellationToken);

            await _mqttClient.DisconnectAsync(cancellationToken);
            _mqttClient?.Dispose();

            await base.StopAsync(cancellationToken);
        }
    }
}